package org.light.simpleauth;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.exception.ValidateException;
import org.light.generator.Generator;
import org.light.utils.WriteableUtil;

public class PasswordUtilGenerator extends Generator{
	protected Domain userDomain;

	public PasswordUtilGenerator(Domain userDomain){
		super();
		this.setUserDomain(userDomain);
		super.fileName = "PasswordUtil.java";
	}

	public Domain getUserDomain() {
		return userDomain;
	}

	public void setUserDomain(Domain userDomain) {
		this.userDomain = userDomain;
	}

	@Override
	public StatementList generateStatementList() throws ValidateException {
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(1000L,0,"package "+this.userDomain.getPackageToken()+".utils;"));
		sList.add(new Statement(2000L,0,""));
		sList.add(new Statement(3000L,0,"import java.security.MessageDigest;"));
		sList.add(new Statement(4000L,0,"import java.sql.Connection;"));
		sList.add(new Statement(5000L,0,"import java.sql.PreparedStatement;"));
		sList.add(new Statement(6000L,0,"import java.sql.ResultSet;"));
		sList.add(new Statement(7000L,0,""));
		sList.add(new Statement(8000L,0,"import "+this.userDomain.getPackageToken()+".database.DBConf;"));
		sList.add(new Statement(9000L,0,""));
		sList.add(new Statement(10000L,0,"public class PasswordUtil {"));
		sList.add(new Statement(11000L,1,"public  static String generateRandomSalt() throws Exception{"));
		sList.add(new Statement(12000L,2,"String token = \"\";"));
		sList.add(new Statement(13000L,2,"char [] pinletters = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};"));
		sList.add(new Statement(14000L,0,""));
		sList.add(new Statement(15000L,2,"do {"));
		sList.add(new Statement(16000L,3,"token = \"\";"));
		sList.add(new Statement(17000L,2,"for(int i=0;i<32;i++)"));
		sList.add(new Statement(18000L,2,"{"));
		sList.add(new Statement(19000L,3,"token += pinletters[(int)(Math.random()*16)];"));
		sList.add(new Statement(20000L,2,"}"));
		sList.add(new Statement(21000L,2,"}while (!uniqueSalt(token));"));
		sList.add(new Statement(22000L,2,"return token;"));
		sList.add(new Statement(23000L,1,"}"));
		sList.add(new Statement(24000L,1,""));
		sList.add(new Statement(25000L,1,"public static boolean uniqueSalt(String salt) throws Exception, Exception{"));
		sList.add(new Statement(26000L,1,"try (Connection connection = DBConf.initDB()) {"));
		sList.add(new Statement(27000L,3,"try {"));
		sList.add(new Statement(28000L,4,"String query = \"select count(*) as countNum from sys_users where salt = ?;\";"));
		sList.add(new Statement(29000L,4,"PreparedStatement ps = connection.prepareStatement(query);"));
		sList.add(new Statement(30000L,4,"ps.setString(1,salt);"));
		sList.add(new Statement(31000L,4,"ResultSet result = ps.executeQuery();"));
		sList.add(new Statement(32000L,4,"Long recordcount = 0L;"));
		sList.add(new Statement(33000L,4,"while(result.next()) {"));
		sList.add(new Statement(34000L,5,"recordcount = result.getLong(\"countNum\");"));
		sList.add(new Statement(35000L,4,"}"));
		sList.add(new Statement(36000L,4,"return recordcount == 0;"));
		sList.add(new Statement(37000L,3,"}catch (Exception e){"));
		sList.add(new Statement(38000L,4,"return false;"));
		sList.add(new Statement(39000L,3,"}"));
		sList.add(new Statement(40000L,2,"}"));
		sList.add(new Statement(41000L,1,"}"));
		sList.add(new Statement(42000L,0,""));
		sList.add(new Statement(43000L,1,"public static boolean verifyPassword(String password, String salt, String encryptPassword) throws Exception{"));
		sList.add(new Statement(44000L,2,"String passwordCheck = multiSha1(password,salt,3);"));
		sList.add(new Statement(45000L,2,"return encryptPassword.equals(passwordCheck);"));
		sList.add(new Statement(46000L,1,"}"));
		sList.add(new Statement(47000L,1,""));
		sList.add(new Statement(48000L,1,""));
		sList.add(new Statement(49000L,1,"public static byte [] mysha1(byte [] data) throws Exception{"));
		sList.add(new Statement(50000L,2,"MessageDigest mdTemp = MessageDigest.getInstance(\"SHA1\");"));
		sList.add(new Statement(51000L,2,"mdTemp.update(data);"));
		sList.add(new Statement(52000L,2,"byte[] md = mdTemp.digest();"));
		sList.add(new Statement(53000L,2,"return md;"));
		sList.add(new Statement(54000L,1,"}"));
		sList.add(new Statement(55000L,1,""));
		sList.add(new Statement(56000L,1,"public static String multiSha1(String password, String salt, int iter) throws Exception {"));
		sList.add(new Statement(57000L,2,"byte [] b = password.getBytes(\"UTF-8\");"));
		sList.add(new Statement(58000L,2,"byte [] s = salt.getBytes(\"UTF-8\");"));
		sList.add(new Statement(59000L,2,"s = merge(s,b);"));
		sList.add(new Statement(60000L,0,""));
		sList.add(new Statement(61000L,2,"for (int i = 0; i < iter;i++) {"));
		sList.add(new Statement(62000L,3,"s = mysha1(s);"));
		sList.add(new Statement(63000L,2,"}"));
		sList.add(new Statement(64000L,2,"StringBuilder hexString = new StringBuilder();"));
		sList.add(new Statement(65000L,2,"for (byte bb : s) {"));
		sList.add(new Statement(66000L,3,"String hex = Integer.toHexString(0xff & bb);"));
		sList.add(new Statement(67000L,3,"if (hex.length() == 1) {"));
		sList.add(new Statement(68000L,4,"hexString.append('0');"));
		sList.add(new Statement(69000L,3,"}"));
		sList.add(new Statement(70000L,3,"hexString.append(hex);"));
		sList.add(new Statement(71000L,2,"}"));
		sList.add(new Statement(72000L,2,"return hexString.toString();"));
		sList.add(new Statement(73000L,1,"}"));
		sList.add(new Statement(74000L,1,""));
		sList.add(new Statement(75000L,1,"public static byte[] merge(byte[] array1, byte[] array2) {"));
		sList.add(new Statement(76000L,2,"byte[] result = new byte[array1.length + array2.length];"));
		sList.add(new Statement(77000L,2,"System.arraycopy(array1, 0, result, 0, array1.length);"));
		sList.add(new Statement(78000L,2,"System.arraycopy(array2, 0, result, array1.length, array2.length);"));
		sList.add(new Statement(79000L,2,"return result;"));
		sList.add(new Statement(80000L,1,"}"));
		sList.add(new Statement(81000L,0,"}"));
		
		return WriteableUtil.merge(sList);
	}
}
